package My

import (
	"fmt"
	"db2s/parDef"
	"strings"
)

func bitMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ShowValue {
	case 0:
		cType = fmt.Sprintf("bit")
	default:
		cType = fmt.Sprintf("bit(%v)", s.Type.ShowValue)
	}
	cByte = 1
	return
}
func intMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ColTypeMap {
	case "int":
		switch {
		case s.Type.ShowValue >= -128 && s.Type.ShowValue <= 127:
			cType = fmt.Sprintf("TINYINT")
		case s.Type.ShowValue >= -32768 && s.Type.ShowValue <= 32767:
			cType = fmt.Sprintf("SMALLINT")
		case s.Type.ShowValue >= -8388608 && s.Type.ShowValue <= 8388607:
			cType = fmt.Sprintf("MEDIUMINT")
		case s.Type.ShowValue >= -2147483648 && s.Type.ShowValue <= 2147483647:
			cType = fmt.Sprintf("INT")
		default:
			cType = fmt.Sprintf("BIGINT")
		}
	case "showString":
		cType = fmt.Sprintf("%v", s.Type.ShowString)
	}
	if s.Type.Symbol {
		cType = fmt.Sprintf("%v UNSIGNED ", cType)
	}
	if s.Type.Zerofill {
		cType = fmt.Sprintf("%v ZEROFILL ", cType)
	}
	return
}
func floatMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ColTypeMap {
	case "float(precision)":
		cType = fmt.Sprintf("float(%v)", s.Type.ShowValue)
		if s.Type.ShowValue > 23 && s.Type.ShowValue < 54 {
			cType = fmt.Sprintf("%v", "double")
		}
	case "float(precision,scale)":
		cType = fmt.Sprintf("float(%v,%v)", s.Type.ShowValue, s.Type.Scale)
		if s.Type.ShowValue > 23 && s.Type.ShowValue < 54 {
			cType = fmt.Sprintf("%v", "double")
		}
	}
	if s.Type.Symbol {
		cType = fmt.Sprintf("%v UNSIGNED ", cType)
	}
	cByte = 4
	return
}
func doubleMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	//double不需要指定长度
	cType = fmt.Sprintf("double")
	switch s.Type.ColTypeMap {
	case "double(precision)":
		cType = fmt.Sprintf("double(%v)", s.Type.ShowValue)
	case "double(precision,scale)":
		cType = fmt.Sprintf("double(%v,%v)", s.Type.ShowValue, s.Type.Scale)
	}
	if s.Type.Symbol {
		cType = fmt.Sprintf("%v UNSIGNED ", cType)
	}
	cByte = 8
	return
}
func decimalMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	if s.ColAutoIncrement {
		return fmt.Sprintf("bigint unsigned"), 8
	}
	switch s.Type.ColTypeMap {
	case "decimal(max,max)":
		return fmt.Sprintf("decimal(65,30)"), CalculateDecimalSize(65)
	case "decimal(precision,scale)":
		return fmt.Sprintf("decimal(%v,%v)", s.Type.Precision, s.Type.Scale), CalculateDecimalSize(s.Type.Precision)
	default:
		return fmt.Sprintf("decimal(%v,%v)", s.Type.Precision, s.Type.Scale), CalculateDecimalSize(s.Type.Precision)
	}
}

func charMapSwitch(s parDef.ColMetaMapS, factor int) (cType string, cByte int) {
	switch {
	case s.Type.ColTypeMap == "char(show)":
		if !s.Type.Variable && s.Type.ShowValue <= 255 {
			return fmt.Sprintf("char(%v)", s.Type.ShowValue), int(s.Type.ShowValue) * factor
		}
		cType = fmt.Sprintf("varchar(%v)", s.Type.ShowValue)
		cByte = int(s.Type.ShowValue) * factor
		if s.Type.ShowValue > 255 {
			cByte = cByte + 2
		} else {
			cByte = cByte + 1
		}
	case s.Type.ColTypeMap == "varchar(show)":
		cType = fmt.Sprintf("varchar(%v)", s.Type.ShowValue)
		cByte = int(s.Type.ShowValue) * factor
		if s.Type.ShowValue > 255 {
			cByte = cByte + 2
		} else {
			cByte = cByte + 1
		}
	}
	return
}

func timeMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ColTypeMap {
	case "year-month-day":
		return fmt.Sprintf("date"), 3
	case "hour:minute:second":
		return fmt.Sprintf("time(0)"), 3
	case "hour:minute:second.milli(1)", "hour:minute:second.milli(2)", "hour:minute:second.milli(3)":
		return fmt.Sprintf("time(%v)", 3), 3
	case "hour:minute:second.micro(1)", "hour:minute:second.micro(2)", "hour:minute:second.micro(3)":
		return fmt.Sprintf("time(%v)", 6), 3
	case "hour:minute:second.nano(1)", "hour:minute:second.nano(2)", "hour:minute:second.nano(3)":
		return fmt.Sprintf("time(6)"), 3
	case "year":
		return fmt.Sprintf("year"), 1
	case "year-month-day hour:minute:second":
		return fmt.Sprintf("datetime(%v)", 0), 8
	case "year-month-day hour:minute:second.milli(1)", "year-month-day hour:minute:second.milli(2)", "year-month-day hour:minute:second.milli(3)":
		return fmt.Sprintf("datetime(%v)", 3), 8
	case "year-month-day hour:minute:second.micro(1)", "year-month-day hour:minute:second.micro(2)", "year-month-day hour:minute:second.micro(3)":
		return fmt.Sprintf("datetime(%v)", 6), 8
	case "year-month-day hour:minute:second.nano(1)", "year-month-day hour:minute:second.nano(2)", "year-month-day hour:minute:second.nano(3)":
		return fmt.Sprintf("datetime(6)"), 8
	}
	return
}
func timestampMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ColTypeMap {
	case "year-month-day hour:minute:second":
		return fmt.Sprintf("datetime(%v)", 0), 4
	case "year-month-day hour:minute:second.utc":
		return fmt.Sprintf("timestamp(%v)", 0), 4
	case "year-month-day hour:minute:second.milli(1)", "year-month-day hour:minute:second.milli(2)", "year-month-day hour:minute:second.milli(3)":
		return fmt.Sprintf("datetime(%v)", 3), 4
	case "year-month-day hour:minute:second.milli(1).utc", "year-month-day hour:minute:second.milli(2).utc", "year-month-day hour:minute:second.milli(3).utc":
		return fmt.Sprintf("timestamp(%v)", 3), 4
	case "year-month-day hour:minute:second.micro(1).utc", "year-month-day hour:minute:second.micro(2).utc", "year-month-day hour:minute:second.micro(3).utc":
		return fmt.Sprintf("timestamp(%v)", 6), 4
	case "year-month-day hour:minute:second.micro(1)", "year-month-day hour:minute:second.micro(2)", "year-month-day hour:minute:second.micro(3)":
		return fmt.Sprintf("datetime(%v)", 6), 4
	case "year-month-day hour:minute:second.nano(1)", "year-month-day hour:minute:second.nano(2)", "year-month-day hour:minute:second.nano(3)":
		return fmt.Sprintf("datetime(6)"), 4
	case "year-month-day hour:minute:second.nano(1).utc", "year-month-day hour:minute:second.nano(2).utc", "year-month-day hour:minute:second.nano(3).utc":
		return fmt.Sprintf("timestamp(6)"), 4
	}
	return
}
func textMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch {
	case s.Type.ShowValue <= 255:
		cType = fmt.Sprintf("TINYTEXT")
	case s.Type.ShowValue <= 65535:
		cType = fmt.Sprintf("TEXT")
	case s.Type.ShowValue <= 16777215:
		cType = fmt.Sprintf("MEDIUMTEXT")
	case s.Type.ShowValue <= 4294967295:
		cType = fmt.Sprintf("LONGTEXT")
	default:
		cType = fmt.Sprintf("LONGTEXT")
	}
	return
}
func jsonMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ColTypeMap {
	case "json":
		switch {
		default:
			cType = fmt.Sprintf("json")
		}
	}
	return
}
func enumMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ColTypeMap {
	case "enum(showString)":
		cType = fmt.Sprintf("enum(%v)", s.Type.ShowString)
	case "set(showString)":
		cType = fmt.Sprintf("set(%v)", s.Type.ShowString)
	}
	return
}
func lobMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch {
	case s.Type.ColTypeMap == "binary(show)":
		switch {
		case s.Type.ShowValue < 255:
			cType = fmt.Sprintf("BINARY(%v)", s.Type.ShowValue)
		case s.Type.ShowValue == 255:
			cType = fmt.Sprintf("BINARY")
		case s.Type.ShowValue < 65535:
			cType = fmt.Sprintf("VARBINARY(%v)", s.Type.ShowValue)
		case s.Type.ShowValue == 65535:
			cType = fmt.Sprintf("VARBINARY")
		default:
			cType = fmt.Sprintf("VARBINARY")
		}
	case s.Type.ColTypeMap == "binary":
		switch {
		case s.Type.ShowValue <= 255:
			cType = fmt.Sprintf("TINYBLOB")
		case s.Type.ShowValue <= 65535:
			cType = fmt.Sprintf("BLOB")
		case s.Type.ShowValue <= 16777215:
			cType = fmt.Sprintf("MEDIUMBLOB")
		case s.Type.ShowValue <= 4294967296:
			cType = fmt.Sprintf("LONGBLOB")
		default:
			cType = fmt.Sprintf("LONGBLOB")
		}
	}
	return
}
func gisMapSwitch(s parDef.ColMetaMapS) (cType string, cByte int) {
	switch s.Type.ColTypeMap {
	case "point": //点
		cType = fmt.Sprintf("POINT")
	case "linestring":
		cType = fmt.Sprintf("LINESTRING")
	case "multipoint": //点集合
		cType = fmt.Sprintf("MULTIPOINT")
	case "line": //线
		cType = fmt.Sprintf("LINESTRING")
	case "multilinestring": //线集合
		cType = fmt.Sprintf("MULTILINESTRING")
	case "polygon": //多边形
		cType = fmt.Sprintf("POLYGON")
	case "multipolygon": //多边形集合
		cType = fmt.Sprintf("MULTIPOLYGON")
	case "geometry": //三维空间   主要单位是度，用于立体
		cType = fmt.Sprintf("GEOMETRY")
	case "multigeometry":
		cType = fmt.Sprintf("MULTIGEOMETRY")
	case "geomcollection":
		cType = fmt.Sprintf("GEOMCOLLECTION")
	}
	return
}
func colTypeMapSwitch(s parDef.ColMetaMapS, factor int) (cType string, cByte int) {
	switch s.TypeBelong {
	case "bit":
		return bitMapSwitch(s)
	case "int", "numerical":
		return intMapSwitch(s)
	case "decimal":
		return decimalMapSwitch(s)
	case "float":
		return floatMapSwitch(s)
	case "double":
		return doubleMapSwitch(s)
	case "char":
		return charMapSwitch(s, factor)
	case "time":
		return timeMapSwitch(s)
	case "timestamp":
		return timestampMapSwitch(s)
	case "text", "longtext":
		return textMapSwitch(s)
	case "json":
		return jsonMapSwitch(s)
	case "enum", "set":
		return enumMapSwitch(s)
	case "lob":
		return lobMapSwitch(s)
	case "gis":
		return gisMapSwitch(s)
	}
	return
}
func defaultValueMapSwitch(convertDataType, dataType string, l string) string {
	switch l {
	case "yearMonthDay":
		return fmt.Sprintf("(DATE_FORMAT(CURRENT_TIMESTAMP(0),%v))", "'%Y%m%d'")
	case "year-month-day hour:minute:second.micro(3).utc", "year-month-day hour:minute:second.micro(3)", "year-month-day hour:minute:second.nano(1)", "year-month-day hour:minute:second.nano(1).utc", "year-month-day hour:minute:second.nano(2)", "year-month-day hour:minute:second.nano(2).utc", "year-month-day hour:minute:second.nano(3)", "year-month-day hour:minute:second.nano(3).utc":
		switch dataType {
		case "char":
			return "(CONCAT(CURRENT_TIMESTAMP(6)))"
		case "time":
			return timeTypeDefaultCurrentTimeStampValueConvert(convertDataType)
		default:
			return "CURRENT_TIMESTAMP(6)"
		}
	case "year-month-day hour:minute:second.micro(2).utc", "year-month-day hour:minute:second.micro(2)":
		switch dataType {
		case "char":
			return "(CONCAT(CURRENT_TIMESTAMP(5)))"
		case "time":
			return timeTypeDefaultCurrentTimeStampValueConvert(convertDataType)
		default:
			return "CURRENT_TIMESTAMP(5)"
		}
	case "year-month-day hour:minute:second.micro(1).utc", "year-month-day hour:minute:second.micro(1)":
		switch dataType {
		case "char":
			return "(CONCAT(CURRENT_TIMESTAMP(4)))"
		case "time":
			return timeTypeDefaultCurrentTimeStampValueConvert(convertDataType)
		default:
			return "CURRENT_TIMESTAMP(4)"
		}
	case "year-month-day hour:minute:second.milli(3).utc", "year-month-day hour:minute:second.milli(3)":
		switch dataType {
		case "char":
			return "(CONCAT(CURRENT_TIMESTAMP(3)))"
		case "time":
			return timeTypeDefaultCurrentTimeStampValueConvert(convertDataType)
		default:
			return "CURRENT_TIMESTAMP(3)"
		}
	case "year-month-day hour:minute:second.milli(2).utc", "year-month-day hour:minute:second.milli(2)":
		switch dataType {
		case "char":
			return "(CONCAT(CURRENT_TIMESTAMP(2)))"
		case "time":
			return timeTypeDefaultCurrentTimeStampValueConvert(convertDataType)
		default:
			return "CURRENT_TIMESTAMP(2)"
		}
	case "year-month-day hour:minute:second.milli(1).utc", "year-month-day hour:minute:second.milli(1)":
		switch dataType {
		case "char":
			return "(CONCAT(CURRENT_TIMESTAMP(1)))"
		case "time":
			return timeTypeDefaultCurrentTimeStampValueConvert(convertDataType)
		default:
			return "CURRENT_TIMESTAMP(1)"
		}
	case "year-month-day hour:minute:second", "year-month-day hour:minute:second.value":
		var format = "'%Y-%m-%d %H:%i:%s'"
		switch {
		case dataType == "char":
			return fmt.Sprintf("(DATE_FORMAT(CURRENT_TIMESTAMP(0),%v))", format)
		case dataType == "time" && strings.HasSuffix(l, ".value"):
			//return fmt.Sprintf("(STR_TO_DATE(%v, %v))", funcParameterSplit(getMiddleBracket(l.OldValue))[0], format)
		default:
			r := getMiddleBracket(convertDataType)
			if len(r) == 0 {
				return "CURRENT_TIMESTAMP(0)"
			}
			return fmt.Sprintf("CURRENT_TIMESTAMP(%v)", r)
		}
	case "year-month-day 00:00:00":
		var format = "'%Y-%m-%d 00:00:00'"
		r := getMiddleBracket(convertDataType)
		if len(r) == 0 {
			r = "0"
		}
		switch {
		case dataType == "char":
			return fmt.Sprintf("(DATE_FORMAT(CURRENT_TIMESTAMP(%v),%v))", r, format)
		case dataType == "time" && strings.HasSuffix(l, ".value"):
			//return fmt.Sprintf("(STR_TO_DATE(%v, %v))", funcParameterSplit(getMiddleBracket(l.OldValue))[0], format)
		default:
			return fmt.Sprintf("(DATE_FORMAT(CURRENT_TIMESTAMP(%v),%v))", r, format)
		}
	case "hour:minute:second":
		switch dataType {
		case "char":
			return "(DATE_FORMAT(CURRENT_TIME,'%H:%i:%s'))"
		default:
			return "CURRENT_TIME"
		}
	case "current_user@host":
		return "USER()"
	case "current_sys_user":
		return "SYSTEM_USER()"
	case "randValue":
		return "RAND()"
	case "uuid":
		return "UUID()"
	case "sys_guid":
		return "(sys_guid())"
	case "current_user":
		return "CURRENT_USER()"
	case "current_id":
		return "CONNECTION_ID()"
	default:
		switch {
		case strings.EqualFold(strings.TrimSpace(l), "NULL"):
			return l
		case strings.EqualFold(dataType, "decimal"), strings.EqualFold(dataType, "int"), strings.EqualFold(dataType, "float"), strings.EqualFold(dataType, "double"):
			return l
		default:
			return fmt.Sprintf("'%v'", strings.ReplaceAll(l, "'", "\\'"))
		}
	}
	return l
}
